package com.ft.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ft.dao.BuyorderDao;
import com.ft.dao.MoneyDao;
import com.ft.dao.NeedDao;
import com.ft.dao.UserDao;
import com.ft.domain.Buyorder;
import com.ft.domain.MoneyInfo;
import com.ft.domain.Need;
import com.ft.service.IBuyorderService;
import com.ft.service.INeedService;
import com.ft.utils.ObjectUtils;
import com.ft.websocket.service.ChatEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author com/ft
 * @since 2022-08-24
 */
@Service
public class NeedServiceImpl implements INeedService {
    @Autowired
    private NeedDao needDao;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private UserDao userDao;
    @Autowired
    private MoneyDao moneyDao;
    /**
     * 创建帮我买订单
     * @param order 帮我买订单对象
     * @return 受影响的行数
     */
    @Override
    public int createNeed(Need order) throws IllegalAccessException {

        /**
         * 先存redis,在存数据库，最后存数据库成功后进行校验，保证数据库和redis里都有数据并且一致
         *  1.封装订单编号，存入buyorderZset所有订单集合中
         *  oldBuyOrderId: 获取添加Zset前的个数
         *  id ：订单id
         */
        Long oldBuyOrderId = redisTemplate.opsForZSet().zCard("needId");
        String id = String.valueOf(order.getId());
        redisTemplate.opsForZSet().add("needId",id,0);
        /**
         *  2.将订单号存入用户的未付款的set里
         * 格式：订单类型 : 用户id : nopay
         * orderKey :封装的key
         * oldlistsize: 添加前的用户未付款set集合长度
         */
        int userid = order.getIssueUser ();
        String orderKey = "need:"+userid+":nopay";
        Long oldlistsize = redisTemplate.opsForSet().size (orderKey);
        redisTemplate.boundSetOps(orderKey).add(id);
        /**
         *  3.封装订单信息，存入Hsah里
         *  格式：订单类型 : 用户id : 订单号
         *  orderKey1：封装hash的key值
         *  stringObjectMap：得到对象属性的map集合
         */
        String orderKey1 = "need:"+order.getId ();
        Map<String, Object> stringObjectMap = ObjectUtils.objectToMap (order);
        redisTemplate.opsForHash ().putAll (orderKey1, stringObjectMap);
        /**
         * 4.将数据存入数据库
         */
        int need = needDao.createNeed(order);
        /**
         * 数据校验，保证数据一致性
         * newBuyOrderId：获取添加后的所有订单的Zset个数
         * newlistsize:添加后的用户未付款list集合长度
         * hashOrderStr：获取存入redis的数据
         * hashOrderSize ：订单表所有字段的和
         */
        if (need == 1 ){
            while (true){
                Long newBuyOrderId = redisTemplate.opsForZSet().zCard("needId");
                Long newlistsize = redisTemplate.opsForSet ().size (orderKey);
                Long  hashOrderSize = redisTemplate.opsForHash().size (orderKey1);
                //结束条件
                if(newBuyOrderId > oldBuyOrderId & newlistsize > oldlistsize & hashOrderSize == Need.total){
                    break;
                }
                //对存入订单id进行校验
                if(newBuyOrderId <= oldBuyOrderId){
                    redisTemplate.opsForZSet().add("needId",id,0);
                    continue;
                }
                //对存入用户未付款set集合进行校验
                if (newlistsize <= oldlistsize){
                    redisTemplate.boundSetOps(orderKey).add(id);
                    continue;
                }
                //对hash订单表进行校验
                if(hashOrderSize != Need.total){
                    //移除key
                    redisTemplate.delete (orderKey1);
                    //重新添加
                    Map<String, Object> stringObjectMap1 = ObjectUtils.objectToMap (order);
                    Set mapkey1 = stringObjectMap.keySet ();
                    for(Object key : mapkey1){
                        redisTemplate.opsForHash().put(orderKey1,key,stringObjectMap.get (key));
                    }
                }
            }
            //同步订单创建时间
            redisTemplate.opsForHash().delete(orderKey1,"createTime");
            String time = needDao.getcreateTime (order.getId ());
            redisTemplate.opsForHash().put(orderKey1,"createTime",time);
            return 1;
        }else {
            //存入数据库失败，删除缓存数据
            redisTemplate.boundZSetOps ("needId").remove (id);
            redisTemplate.boundSetOps(orderKey).remove (id);
            redisTemplate.delete (orderKey1);
            return 0;
        }
    }

    /**
     * 查询订单的所有信息
     * @param id 订单id
     * @return
     */
    @Override
    public Need selectNeed(Long id) {
        Need need = needDao.selectNeed(id);
        return need;
    }

    /**
     * 查询用于支付订单的信息
     * @param id 订单id
     * @return
     */
    @Override
    public Need selectNeedToPay(Long id) {
        Need need = needDao.selectNeedToPay(id);
        return need;
    }

    /**
     * 付款后，修改订单状态
     * @return 返回受影响的结果
     */
    @Override
    public int updataOrder(int state,String id,int userid) {
        int i = needDao.updataOrder (state,id);
        String key ="need:"+id;
        if(i == 1){
            //移除用户未支付set里的订单数据
            redisTemplate.opsForSet ().remove ("need:"+userid+":nopay",id);
            //向用户已支付set里添加数据
            redisTemplate.opsForSet ().add ("need:"+userid+":okpay",id);
            //将订单类型zet集合中的对应订单id的score值加1
            redisTemplate.opsForZSet().incrementScore ("needId",id,1);
            //修改订单hash表state状态
            redisTemplate.opsForHash().delete(key,state);
            redisTemplate.opsForHash().put(key,"state",1);
            //更新订单时间
            redisTemplate.opsForHash().delete(key,"updateTime");
            String time = needDao.getupdateTime(Long.valueOf (id));
            redisTemplate.opsForHash().put(key,"updateTime",time);
            return 1;
        }else {
            return 0;
        }
    }
    /**
     * 懒人中心分页获取订单数据
     * @param page
     * @return
     */
    @Override
    public List getOrder(int page) {
        //返回结果集合
        List result = new ArrayList ();
        //获取所有订单数据
        Set needId = redisTemplate.opsForZSet ().reverseRangeByScore("needId", 1, 999);
        //如果数据小于5的情况
        if(needId.size() < 5){
            List ids = new ArrayList<>(needId);
            //获取订单数据返回
            for(int i = 0;i < ids.size(); i++){
                Map entries = redisTemplate.opsForHash ().entries ("need:" + ids.get (i));
                if((int)entries.get("state") == 1) {
                    //对订单号处理成字符串，防止前端精度丢失
                    Object id = entries.get("id");
                    entries.put("id", "" + id);
                    result.add(entries);
                }
            }
            return result;
        }
        //数据大于5的情况
        //将set集合转换成list
        List ids = new ArrayList<>(needId);
        //每次返回5个数据，total：获取数据结束的位置
        int total = 0;
        //每次获取数据循环开始的位置
        int num = page * 5;
        if(page == 0){
            total = 5;
        }else {
            total = (page+1) * 5;
        }
        for(;num < total & num < needId.size (); num++){
            Map entries = redisTemplate.opsForHash ().entries ("need:" + ids.get (num));
            if((int)entries.get("state") == 1) {
                //对订单号处理成字符串，防止前端精度丢失
                Object id = entries.get("id");
                entries.put("id", "" + id);
                result.add(entries);
            }
        }
        //获取分页数据
        return result;
    }

    /**
     * 搜索内容
     * @param content 搜索的数据
     * @return
     */
    @Override
    public List search(String content) {
        //返回结果集合
        List result = new ArrayList ();
        if("".equals(content) | content == null | content.length() == 0) {
            System.out.println("进入空了");
            return result;
        }
        //获取所有已支付订单数据
        Set buyorderId = redisTemplate.opsForZSet ().reverseRangeByScore("needId", 1, 999);
        //遍历集合取出数据
        for(Object key : buyorderId){
            Map entries = redisTemplate.opsForHash ().entries ("need:" + key);
            if((int)entries.get("state") == 1) {
                //对订单号处理成字符串，防止前端精度丢失
                String ct = (String) entries.get ("content");
                if(ct.contains (content)){
                    result.add(entries);
                }
            }

        }
        return result;
    }

    /**
     * 获取用户以发布订单
     *
     * @param userid
     * @return
     */

    @Override
    public List getIssueOrderListByUser(String userid) {
        //返回结果集合
        List result = new ArrayList();
        //获取已付款订单数据
        Set orderOkId = redisTemplate.boundSetOps("need:" + userid + ":okpay").members();
        List ids = new ArrayList<>(orderOkId);
        //获取订单数据返回
        for (int i = 0; i < ids.size(); i++) {
            Map entries = redisTemplate.opsForHash().entries("need:" + ids.get(i));
            //对订单号处理成字符串，防止前端精度丢失
            Object id = entries.get("id");
            entries.put("id", "" + id);
            result.add(entries);
        }
        //获取未付款订单数据
        Set orderNoId = redisTemplate.boundSetOps("need:" + userid + ":nopay").members();
        List ids2 = new ArrayList<>(orderNoId);
        //获取订单数据返回
        for (int i = 0; i < ids2.size(); i++) {
            Map entries = redisTemplate.opsForHash().entries("need:" + ids2.get(i));
            //对订单号处理成字符串，防止前端精度丢失
            Object id = entries.get("id");
            entries.put("id", "" + id);
            result.add(entries);
        }
        return result;
    }

    /**
     * 获取用户已接单订单
     *
     * @param userid
     * @return
     */

    @Override
    public List getOrderListByUser(String userid) {
        List result = new ArrayList();
        Set orderOkId = redisTemplate.boundSetOps(userid+"needissueorder").members();
        List ids = new ArrayList<>(orderOkId);
        //获取订单数据返回
        for (int i = 0; i < ids.size(); i++) {
            Map entries = redisTemplate.opsForHash().entries("need:" + ids.get(i));
            //对订单号处理成字符串，防止前端精度丢失
            Object id = entries.get("id");
            entries.put("id", "" + id);
            result.add(entries);
        }
        return result;
    }

    /**
     * 退款后修改订单状态
     *
     * @param
     * @return
     */

    @Override
    public int updateOrderRefund(String orderid) {
        int i = needDao.refundState(orderid);
        if(i == 1){
            //处理缓存
            String key = "need:" + orderid;
            //修改订单hash表state状态
            redisTemplate.opsForHash().put(key, "state", 5);
            String time = needDao.getupdateTime(Long.valueOf(orderid));
            redisTemplate.opsForHash().put(key, "updateTime", time);
            return 1;
        }
        return 0;
    }

    /**
     * 接单用户完成订单，确认修改订单状态
     *
     * @return
     */

    @Override
    public int accomplishOrder(String orderid) throws IOException, IllegalAccessException {
        //获取订单信息
        Need order = needDao.selectNeed(Long.valueOf(orderid));
        if(order.getState() != 2 ){
            return  2;
        }
        String username = userDao.selectUserByID(String.valueOf(order.getBelongUser()));
        int i = needDao.accomplishOrder(orderid);
        if(i == 1){
            //修改缓存中的订单状态
            String key = "need:" + orderid;
            //修改订单hash表state状态
            redisTemplate.opsForHash().put(key, "state", 3);
            String time = needDao.getupdateTime(Long.valueOf(orderid));
            redisTemplate.opsForHash().put(key, "updateTime", time);
            //设置消息内容
            String msg = "用户:"+username +"点击了完成订单，如果没有问题请您在订单中心确认订单完结";
            int T = ChatEndpoint.orderMessage(String.valueOf(order.getIssueUser()),username,msg);
            if(T == 1){
                return 1;
            }
            return 0;
        }
        return 0;
    }


    /**
     * 发布用户确认完成订单
     * @param orderid
     * @return
     */
    @Override
    public int issueOverOrder(String orderid, int userid) throws IOException, IllegalAccessException {
        //获取订单信息
        Need order = needDao.selectNeed(Long.valueOf(orderid));
        if(order.getState() != 3 ){
            return  2;
        }
        String username = order.getIssueUserName();
        int i = needDao.issueaccomplishOrder(orderid);
        // 修改对应用户的金额
        //手续费
        BigDecimal rate = new BigDecimal(""+0.06);
        //订单价格
        BigDecimal money = new BigDecimal(""+order.getPrice());
        //接单用户的收入
        BigDecimal income = money.subtract(money.multiply(rate));
        //结果保留2位小数，4舍，5入
        double requestMoney = income.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        //获取接单用户的money
        double userMoney = userDao.getUserMoney(order.getBelongUser());
        //对精度处理
        BigDecimal p1 = new BigDecimal(Double.toString(requestMoney));
        BigDecimal p2 = new BigDecimal(Double.toString(userMoney));
        //总价
        BigDecimal tataleMoney = p1.add(p2);
        //更新发布用户金额
        int i1 = userDao.updateUserMoney(tataleMoney, order.getBelongUser());
        //创建交易明细表
        MoneyInfo moneyInfo = new MoneyInfo();
        moneyInfo.setMoney(requestMoney);
        moneyInfo.setIssueuser(order.getIssueUser());
        moneyInfo.setContinueuser(order.getBelongUser());
        moneyInfo.setGetmoenyorderid(order.getId());
        int i2 = moneyDao.addMoneyInfo(moneyInfo);
        if(i == 1 & i1 == 1 & i2 == 1){
            //修改缓存中的订单状态
            String key = "need:" + orderid;
            //修改订单hash表state状态
            redisTemplate.opsForHash().put(key, "state", 4);
            String time = needDao.getupdateTime(Long.valueOf(orderid));
            redisTemplate.opsForHash().put(key, "updateTime", time);
            //设置消息内容
            String msg = "用户:"+username +"确认完成了订单"+ requestMoney +"元已到账！";
            int T = ChatEndpoint.orderMessage(String.valueOf(order.getBelongUser()),username,msg);
            if(T == 1){
                return 1;
            }
            return 0;
        }
        return 0;
    }


    /**
     * 用户接单
     *
     * @param userid
     * @return
     */

    @Override
    public int UserOrder(String orderid,int userid) throws IOException, IllegalAccessException {
        //获取订单信息
        Need order = needDao.selectNeed(Long.valueOf(orderid));
        if(order.getState() == 2 ){
            return  2;
        }
        String username = userDao.selectUserByID(String.valueOf(userid));
        int state = needDao.selectState(orderid);
        if(state == 2){
            return 2;
        }
        //先修改数据库中的订单状态
        int i = needDao.UserOrder(orderid, userid);
        if(i == 1){
            //修改成功后修改缓存中的订单状态
            String key = "need:" + orderid;
            //修改订单hash表state状态
            redisTemplate.opsForHash().put(key, "state", 2);
            redisTemplate.opsForHash().put(key, "belongUser", userid);
            //向用户接单set中添加数据
            redisTemplate.boundSetOps(userid+"needissueorder").add(orderid);
            //更新订单时间
            redisTemplate.opsForHash().delete(key, "updateTime");
            String time = needDao.getupdateTime(Long.valueOf(orderid));
            redisTemplate.opsForHash().put(key, "updateTime", time);
            //设置消息内容
            String msg = "订单标题为:"+order.getTitle()+"的订单,被用户:"+username +"接单了";
            int T = ChatEndpoint.orderMessage(String.valueOf(order.getIssueUser()),username,msg);
            if(T == 1){
                return 1;
            }
            return 0;
        }else {
            return 0;
        }
    }

    /**
     * 用户取消订单
     * @param orderid
     * @return
     */
    @Override
    public int OverUserOrder(String orderid,int userid) throws IOException, IllegalAccessException {
        //获取订单信息
        Need order = needDao.selectNeed(Long.valueOf(orderid));
        if(order.getState() == 2 ){

        }
        if(order.getState() != 2 ){
            return  2;
        }
        String username = userDao.selectUserByID(String.valueOf(userid));
        //先查询用户是否是完结状态
        int T = needDao.selectState(orderid);
        if(T != 2 ){
            return  2;
        }
        int i = needDao.OverUserOrder(orderid);
        if(i == 1) {
            //更新缓存中的数据
            //修改成功后修改缓存中的订单状态
            String key = "need:" + orderid;
            //修改订单hash表state状态
            redisTemplate.opsForHash().put(key, "state", 1);
            //删除接单用户
            redisTemplate.opsForHash().put(key, "belongUser","");
            //移除用户接单set中的数据
            redisTemplate.opsForSet().remove(userid+"needissueorder", orderid);
            //更新订单时间
            redisTemplate.opsForHash().delete(key, "updateTime");
            String time = needDao.getupdateTime(Long.valueOf(orderid));
            redisTemplate.opsForHash().put(key, "updateTime", time);
            //设置消息内容
            String msg = "订单标题为:"+order.getTitle()+"的订单,被用户:"+username +"取消了";
            int T1 = ChatEndpoint.orderMessage(String.valueOf(order.getIssueUser()),username,msg);
            if(T1 == 1){
                return 1;
            }
            return 0;
        }
        return 0;
    }

}
